#!usr/bin/python
# coding=utf-8

from localsystem import localsystem
from datetime import datetime
import shlex
import time
import os
import re
import sys
import urllib2
import tarfile
import shutil
from xml.dom.minidom import parse
import xml.dom.minidom
from components.logger import logger
from utils.TimeUtils import get_during_seconds_from_now2
import threading
import multiprocessing


class device(object):
    """
    出事化设备对象， sn，序列号； state，设备状态； ss，系统对象（用于执行本地操作）; ws, 当前是否正在执行任务。
    """
    xmlpathindevice = "/sdcard/window_dump.xml"

    def __init__(self, sn, state, ss, workstate):
        self.sn = sn
        self.state = state
        self.cmd = ss
        self.ws = workstate

    def __getWindowDump(self):
        """
        dump当前页面的window_dump.xml文件
        """
        dumpfilepath = "./" + self.sn + ".xml"
        if os.path.exists(dumpfilepath):
            os.remove(dumpfilepath)
        self.setScreenOn()
        cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell uiautomator dump")
        if "error" in ''.join(cmdout):
            return False, None
        cmdout = self.cmd.commandActuator(
            "adb -s " + self.sn + " pull " + self.xmlpathindevice + " " + dumpfilepath)
        if "pulled" in ''.join(cmdout) and os.path.exists(dumpfilepath):
            return True, dumpfilepath
        else:
            return False, None

    def checkScreenIfOnOrOff(self):
        """
        检查屏幕是否点亮
        """
        cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell dumpsys window policy | grep -i awak")
        print cmdout
        if 'mAwake=true' in ''.join(cmdout):
            print True
            return True
        else:
            print False
            return False

    def quickJumpGuide(self):
        """
        快速跳过开机引导页面
        """
        self.cmd.commandActuator("adb -s " + self.sn + " shell settings put global device_provisioned 1")
        self.cmd.commandActuator("adb -s " + self.sn + " reboot")

    def unScreenLock(self):
        """
        解锁屏幕
        """
        # self.setScreenOn()
        bounds = self.__getPosition("resource-id", 'com.android.systemui:id/qs_frame')
        lefttoppoint, rightbuttompoint = re.findall(r'\[[0-9]+,[0-9]+\]', bounds)
        lefttoppoint = eval(lefttoppoint)
        rightbuttompoint = eval(rightbuttompoint)
        half_x = int((rightbuttompoint[0] - lefttoppoint[0]) / 2)
        half_y = int((rightbuttompoint[1] - lefttoppoint[1]) / 2)
        self.swipe([half_x, rightbuttompoint[1]], [half_x, half_y / 4], 200)

    def getpackageinfoindevice(self):
        """
        获取设备中包信息
        """
        cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell pm list packages")
        result = {}
        packages = []
        i = 0
        for line in cmdout:
            if line == "":
                continue
            package = {}
            packagename = line.strip("\n").split(":")[1]
            package["key"] = i
            package["value"] = packagename
            packages.append(package)
            i += 1
        result["packages"] = packages
        return result

    def setScreenOn(self):
        """
        点亮屏幕
        """
        if not self.checkScreenIfOnOrOff():
            cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell input keyevent 26")

    def setScreenOff(self):
        """
        熄灭屏幕
        """
        if self.checkScreenIfOnOrOff():
            cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell input keyevent 26")

    def parseBounds(self, bounds):
        """
        解析坐标点
        """
        lefttoppoint, rightbuttompoint = re.findall(r'\[[0-9]+,[0-9]+\]', bounds)
        lefttoppoint = eval(lefttoppoint)
        rightbuttompoint = eval(rightbuttompoint)
        return lefttoppoint[0] + (rightbuttompoint[0] - lefttoppoint[0]) // 2, lefttoppoint[1] + (
                rightbuttompoint[1] - lefttoppoint[1]) // 2

    def __getPosition(self, atype, value):
        """
        获取resource-id对应的bounds值
        """
        times = 3
        while True:
            result, path = self.__getWindowDump()
            if result:
                domtree = parse(path)
                collection = domtree.documentElement
                nodes = collection.getElementsByTagName("node")
                for node in nodes:
                    if node.hasAttribute("resource-id"):
                        if atype == 'resource-id' and value == str(node.getAttribute("resource-id")):
                            bounds = node.getAttribute("bounds")
                            return bounds
                    if node.hasAttribute("text"):
                        if atype == 'text':
                            if value == unicode(node.getAttribute("text")):
                                bounds = node.getAttribute("bounds")
                                return bounds
            times -= 1
            if times <= 0:
                return ""
            time.sleep(2)

    def checkElementsIfNotExist(self, type, value):
        """
        检测对于的resource-id是否存在
        """
        if type == 0:
            attr = "resource-id"
        elif type == 1:
            attr = "text"
        else:
            pass
        if "" != self.__getPosition(attr, value):
            return True
        else:
            return False

    def click_element_by_ResourceId(self, resourceid, waittime=2):
        """
        点击ByResourceId
        """
        while True:
            if self.checkElementsIfNotExist(0, resourceid):
                point = self.parseBounds(self.__getPosition("resource-id", resourceid))
                cmdout = self.cmd.commandActuator(
                    "adb -s " + self.sn + " shell input tap " + str(point[0]) + " " + str(point[1]))
                break
            else:
                time.sleep(waittime)

    def sendText(self, resourceid, text, waittime=2):
        """
        点击ByResourceId, then send text
        """
        while True:
            if self.checkElementsIfNotExist(0, resourceid):
                point = self.parseBounds(self.__getPosition("resource-id", resourceid))
                cmdout = self.cmd.commandActuator(
                    "adb -s " + self.sn + " shell input tap " + str(point[0]) + " " + str(point[1]))
                cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell input text " + text)
                break
            else:
                time.sleep(waittime)

    def click_element_by_Text(self, text, waittime=2):
        """
        点击ByText
        """
        while True:
            if self.checkElementsIfNotExist(1, text):
                point = self.parseBounds(self.__getPosition("text", text))
                cmdout = self.cmd.commandActuator(
                    "adb -s " + self.sn + " shell input tap " + str(point[0]) + " " + str(point[1]))
                break
            else:
                time.sleep(waittime)

    def swipe(self, point_from, point_to, during):
        # swipe <x1> <y1> <x2> <y2> [duration(ms)]
        cmdout = self.cmd.commandActuator(
            "adb -s " + self.sn + " shell input swipe " + str(point_from[0]) + " " + str(point_from[1]) + " " + str(
                point_to[0]) + " " + str(point_to[1] - 200) + " " + str(during))

    def get_packageinfo(self):
        cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell pm list packages")
        if "package:com.miui.voiceassist\n" in cmdout:
            return True
        else:
            return False

    def flashdevice(self, private_logger, flashscriptpath=None):
        """
        刷机
        """
        private_logger.info("flashdevice")
        if flashscriptpath is None:
            return True, None
        # elif flashscriptpath == "test":
        #     flashscriptpath = "/home/mi/下载/imagesrom/polaris_images_1.1.1_20181116.0000.00_8.0_cn"
        #     if not os.path.exists(flashscriptpath):
        #         raise ArgumentsError(r"test入参是脚本开发这本地的环境，只用于脚本开发这本地测试使用")
        elif not os.path.exists(flashscriptpath):
            raise ArgumentsError(r"rom刷机脚本路径不存在，1.检查你的入参，2.检查是否存在刷机rom")
        private_logger.info("尝试连接设备并刷机")
        count = 0

        tag = False
        while True:
            cmdout = self.cmd.commandActuator("adb devices")
            index = cmdout.index('List of devices attached\n')
            cmdout = [el for el in cmdout if el not in ['', '\n']][index + 1:]
            cout = len(cmdout)
            # 寻找非fastboot模式下是否存在对应设备，存在开始刷机
            for d in cmdout:
                sn, status = d.strip('\n').split('\t')
                private_logger.info("设备sn：%s, 设备状态：%s" % (str(sn), str(status)))
                if self.sn == sn:
                    if status == "device":
                        cmdout = self.cmd.commandActuator(
                            "adb -s " + self.sn + " reboot bootloader")
                        cmdout = self.cmd.commandActuator(
                            "cd " + flashscriptpath + "; chmod 777 ./flash_all.sh; ./flash_all.sh -s " + self.sn)
                        private_logger.info("刷机信息 %s", str(cmdout))
                        tag = True
                        break
                    else:
                        raise Exception("device is not ready!")
                        return False, "DEVICENOTREADY"
            # 在没有找到设备后，查找在fastboot模式下的手机，进行刷机
            if not tag:
                fastboot_sn_out = self.cmd.commandActuator("fastboot devices")
                fastboot_sn_out = [fel for fel in fastboot_sn_out if fel not in ['', '\n']]
                for fd in fastboot_sn_out:
                    sn, f_tag = fd.strip('\n').split('\t')
                    private_logger.info("fastboot页面, 设备sn：%s, 设备状态：%s" % (str(sn), str(f_tag)))
                    if sn == self.sn:
                        if f_tag == "fastboot":
                            cmdout = self.cmd.commandActuator(
                                "cd " + flashscriptpath + "; chmod 777 ./flash_all.sh; ./flash_all.sh -s " + self.sn)
                            private_logger.info("刷机信息 %s", str(cmdout))
                            tag = True
                            break

            if tag:  # 处理找到设备，但刷机失败的情况
                if 'Flash system error' in ''.join(cmdout):
                    private_logger.info("flash error %s" % str([l for l in cmdout if 'FAILED' in l][0]))
                    return False, "FLASHERROR"
                    break

            count += 1
            if count > 3:
                if not tag:  # 处理3此尝试未找到设备的情况
                    private_logger.info("未找到sn对象的设备")
                    return False, "DEVICENOTFOUND"
                break
            time.sleep(5)

        times = 0  # 45分钟内查询到目标sn
        while True:
            cmdout = self.cmd.commandActuator("adb devices")
            index = cmdout.index('List of devices attached\n')
            cmdout = [el for el in cmdout if el not in ['', '\n']][index + 1:]
            if len(cmdout) >= 1:
                for d in cmdout:
                    sn, status = d.strip('\n').split('\t')
                    if self.sn == sn:
                        private_logger.info("after flash..: %s, %s" % (str(sn), str(status)))
                        if status == "device":
                            private_logger.info('flash ok and devies status is ' + status)
                            return True, None
                        else:
                            return False, "DEVICENOTREADYAFTERFLASH"
            times += 1
            time.sleep(60)
            if times > 45:
                return False, "DEVICENOTFOUNDAFTERFLASH"

    def killall_monkey(self):
        self.cmd.commandActuator("adb -s " + self.sn + " shell killall com.android.commands.monkey")

    def monkey_test(self, commandofmonkeyprogram, taskinfo, expired_seconds, private_logger, result_dir):
        """
        Monkey测试处理
        """

        private_logger.info('begin monkey: %s' % (str(multiprocessing.current_process().pid)))

        def kill_monkey():
            self.cmd.commandActuator("adb -s " + self.sn + " shell killall com.android.commands.monkey")
            private_logger.info('kill monkey: %s' % (str(multiprocessing.current_process().pid)))

        self.set_screen_stay_on()
        if self.checkElementsIfNotExist(0, 'com.android.systemui:id/current_date'):
            private_logger.info('第一次解锁，并等待初始化')
            self.unScreenLock()
        logfile_name = result_dir + str(taskinfo).replace(' ', '_') + "_" + str(os.getppid()) + "_" + str(
            os.getpid()) + '_' + str(datetime.now().date()) + '_' + str(datetime.now().time()) + "_monkey.log"
        threading.Timer(expired_seconds - 600, kill_monkey).start()
        self.cmd.commandActuator("adb -s " + self.sn + " shell " + commandofmonkeyprogram)
        self.cmd.commandActuator("adb -s " + self.sn + " pull " + commandofmonkeyprogram.split(">")[1].lstrip(
            " ").rstrip("'") + " ." + logfile_name)
        private_logger.info('last monkey: %s' % (str(multiprocessing.current_process().pid)))
        return True, logfile_name

    def terminate_monkey_logfile_pull(self, commandofmonkeyprogram, result_dir, taskinfo, private_logger):
        self.cmd.commandActuator("adb -s " + self.sn + " shell killall com.android.commands.monkey")
        private_logger.info('kill monkey: %s' % (str(multiprocessing.current_process().pid)))
        logfile_name = result_dir + str(taskinfo).replace(' ', '_') + "_" + str(os.getppid()) + "_" + str(
            os.getpid()) + '_' + str(datetime.now().date()) + '_' + str(datetime.now().time()) + "_monkey.log"
        self.cmd.commandActuator("adb -s " + self.sn + " pull " + commandofmonkeyprogram.split(">")[1].lstrip(
            " ").rstrip("'") + " ." + logfile_name)
        private_logger.info('last monkey: %s' % (str(multiprocessing.current_process().pid)))
        return logfile_name

    def pull_crash_and_anr_log(self, private_logger, result_dir, taskinfo="task", path='/sdcard'):
        files_list = self.cmd.commandActuator(
            "adb -s " + self.sn + " shell 'cd " + path + "; ls'")

        private_logger.info('files in path %s : %s' % (path, str(files_list)))

        crash_files_list = self.cmd.commandActuator(
            "adb -s " + self.sn + " shell 'cd " + path + "; ls | grep -i crash'")

        private_logger.info('crash files in path %s : %s' % (path, str(crash_files_list)))

        anr_files_list = self.cmd.commandActuator("adb -s " + self.sn + " shell 'cd " + path + "; ls | grep -i anr'")

        private_logger.info('anr files in path %s : %s' % (path, str(anr_files_list)))

        crash_files_list_path = []
        crash_dir = result_dir + 'crashs'
        if not os.path.exists(crash_dir):
            os.mkdir(crash_dir)
        crash_dir += "/"
        for f_c in crash_files_list:
            file_name_crash = str(f_c).strip('\n')
            if f_c in ['', '\n', ' ']:
                continue
            crash_files_list_path.append(crash_dir + str(
                taskinfo).replace(' ', '_') + "_" + file_name_crash)
            self.cmd.commandActuator(
                "adb -s " + self.sn + " pull " + path + "/" + file_name_crash + " " + crash_dir + str(
                    taskinfo).replace(' ', '_') + "_" + file_name_crash)

        anr_files_list_path = []
        anr_dir = result_dir + 'anrs'
        if not os.path.exists(anr_dir):
            os.mkdir(anr_dir)
        anr_dir += "/"
        for f_a in anr_files_list:
            file_name_anr = str(f_a).strip('\n')
            if f_a in ['', '\n', ' ']:
                continue
            anr_files_list_path.append(anr_dir + str(
                taskinfo).replace(' ', '_') + "_" + file_name_anr)
            self.cmd.commandActuator(
                "adb -s " + self.sn + " pull " + path + "/" + file_name_anr + " " + anr_dir + str(
                    taskinfo).replace(' ', '_') + "_" + file_name_anr)

        if anr_files_list_path:
            anr_info_dir = anr_dir + 'anrsinfo'
            if not os.path.exists(anr_info_dir):
                os.mkdir(anr_info_dir)
            anr_info_dir += "/"
            self.cmd.commandActuator('adb root; adb pull /data/anr ' + anr_info_dir)

        return len([e for e in crash_files_list if e not in ['', '\n', ' ']]), crash_files_list_path, len(
            [e for e in anr_files_list if e not in ['', '\n', ' ']]), anr_files_list_path

    def get_device_model(self):
        cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell getprop ro.product.device")
        cmdout = [el for el in cmdout if el not in ['', '\n']]
        return cmdout[0].strip('\n')

    def get_device_product_name(self):
        cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell getprop ro.product.model")
        cmdout = [el for el in cmdout if el not in ['', '\n']]
        return cmdout[0].strip('\n').replace(' ', '_')

    def get_device_region(self):
        cmdout = self.cmd.commandActuator("adb -s " + self.sn + " shell getprop ro.product.locale")
        cmdout = [el for el in cmdout if el not in ['', '\n']]
        return cmdout[0].strip('\n')

    def set_screen_stay_on(self):
        cmdout = self.cmd.commandActuator(
            "adb -s " + self.sn + " shell svc power stayon true")

    def set_screen_not_stay_on(self):
        cmdout = self.cmd.commandActuator(
            "adb -s " + self.sn + " shell svc power stayon false")


class ArgumentsError(Exception):
    pass
